/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package uk.ac.shef.zeno.exercise;

import com.primesense.nite.SkeletonState;
import com.primesense.nite.UserData;
import com.primesense.nite.UserTracker;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 *
 * @author samf
 */
public class ExerciseApp {
    boolean greeted;
    ExerciseUtils eu;
    ExerciseState state;
    PlayState playState;
    UserData activeUser;
    boolean halfwayMark;
    Robot robot;
    private long speechStart;
    private long speechEnd;
    private long sessionStart;
    DecimalFormat df;
    private int sessionLength = 10000;
    DateFormat dateFormat;
    float mass;
    int sessionNo;
    float totalCalories;
    
    public ExerciseApp(UserTracker tracker, PositionPanel panel) {
        state = ExerciseState.NOTHINGNESS;
        playState = PlayState.PLAY_START;
        eu = new ExerciseUtils(tracker, panel);
        robot = new Robot();
        halfwayMark = false;
        df = new DecimalFormat("#.#");
       dateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss.SSS");
       mass = 70;
       sessionNo = 0;
    }


    boolean isAnyoneTracking(List<UserData> users) {
        boolean isAnyoneTracking = false;
        for (UserData user : users) {
            if (user.getSkeleton().getState() == SkeletonState.TRACKED) {
                isAnyoneTracking = true;
            }
        }
        return isAnyoneTracking;
    }

    public void update(List<UserData> users) {
        robot.flushQueue();
        
       if (state == ExerciseState.NOTHINGNESS) {
            if (!users.isEmpty()) {
                state = ExerciseState.BODIES;
                for (UserData user : users) {
                    eu.mTracker.startSkeletonTracking(user.getId());
                }
             //   eu.stopSpeaking();
            } /*else if (eu.speechFinished()) {
                //eu.speak("I am all alone");
            }*/
        }

        if (state == ExerciseState.BODIES) {
            if (users.isEmpty()) {
                state = ExerciseState.NOTHINGNESS;
               // eu.stopSpeaking();
            } else {
                if (isAnyoneTracking(users)) {
                    state = ExerciseState.TRACKING;
                 //   eu.stopSpeaking();
                } else {
                    for (UserData user : users) {
                        //if (user.isNew()) {
                        if (user.getSkeleton().getState() == SkeletonState.NONE) {
                            eu.mTracker.startSkeletonTracking(user.getId());
                        }
                        //}
                    }

                }
            }
        }

        if (state == ExerciseState.TRACKING) {
            System.out.println("Tracking state");
            if (!isAnyoneTracking(users)) {
                state = ExerciseState.BODIES;
               // eu.stopSpeaking();
            } else if (anyoneInZone(users)) {
                state = ExerciseState.INZONE_START_SESSION;
               // eu.stopSpeaking();
            } //else if (eu.speechFinished()) {
                for (UserData user : users) {
                    //if (user.isNew()) {
                    eu.mTracker.startSkeletonTracking(user.getId());
                    //}
                }

                //eu.speak("I can see you. But you have to get into the zone if you want to play.");
            //}
        }

        if (state == ExerciseState.INZONE_START_SESSION) {
            long now = System.currentTimeMillis();
            sessionLength = 10000;
            totalCalories = 0;
            String strNow = dateFormat.format(new Date(now));
            System.out.println(strNow + " start first session");
            if (!anyoneInZone(users)) {
                state = ExerciseState.TRACKING;
            }
           // if (!greeted && eu.speechFinished()) {
            if (!greeted) {
                //eu.speak("Hello! Are you ready to do some exercise? OK let's start by running on the spot. Start slowly at first, to let yourself get warmed up.");
                robot.addSpeech("Hello, I am Zeeno. Today I am going to be your personal trainer. We are going to learn about how much energy you use during exercise. "
                 + "First let's warm up with some slow exercise for ten seconds. Move your arms up and down slowly, and then at the end I will tell you how much energy you used. "
                  + "OK, get ready, I will count down from 3. 3, 2, 1, Go!");
               
   //            robot.addSpeech("OK, Go!");
                robot.addAnimation("happy");
                for (UserData user : users) {
                    if (activeUser!=null && user.getId() != activeUser.getId()) {
                        eu.mTracker.stopSkeletonTracking(user.getId());
                    }
                }
                greeted = true;

            }

            //if (greeted && eu.speechFinished()) {
            if (greeted && robot.speechFinished()) {
                sessionStart = System.currentTimeMillis();
                
                state = ExerciseState.MONITOR_SESSION;
                greeted = false;
                sessionNo = 1;
                robot.log("Speech finished session start "+sessionNo);
            }
            activeUser = getActiveUser(users);

            if (activeUser!=null) {
                eu.makeLog(activeUser, state, playState);
            }
    //        else {
      //          state = ExerciseState.PENDING_GOODBYE;
        //    }

        }
        if (state == ExerciseState.RESTART) {
            robot.log("Restarting session "+sessionNo);
            if (!greeted) {
                robot.addAnimation("happy");
                
                if (sessionNo==1) {
                    robot.addSpeech("OK, now this time, we are going to practise doing some faster exercise for another 10 seconds. You can run on the spot, or jump up and down, do anything you like - but try and move as quickly as you can! OK, get ready, Go!");
                } else if (sessionNo==2) {
                    robot.addSpeech("OK this is the last session. Now you are going to try and get a high a score as you can, and this time you are going to go for 20 seconds instead of 10. OK take a breath, get ready. 3, 2, 1, Go!");
                    sessionLength = 20000;
                }
                greeted = true;
            }
            if (greeted && robot.speechFinished()) {
                sessionStart = System.currentTimeMillis();
                state = ExerciseState.MONITOR_SESSION;
                greeted = false;
                sessionNo+=1;
                robot.log("Speech finished session start "+sessionNo);
            }
             activeUser = getActiveUser(users);

            if (activeUser!=null) {
                eu.makeLog(activeUser, state, playState);
            }
        }
        if (state==ExerciseState.MONITOR_SESSION) {
           
            long now = System.currentTimeMillis();
           robot.log("Monitoring session "+sessionNo);        
              // System.out.println(strNow + " monitoring session "+sessionNo);
         
            activeUser = getActiveUser(users);
            if (activeUser!=null) {
                eu.makeLog(activeUser, state, playState);
              eu.addSkeleton(activeUser.getSkeleton());
              if (now-sessionStart>sessionLength) {
                  state = ExerciseState.SESSION_TIMEOUT;
                  halfwayMark = false;
              }
              else if (!halfwayMark && now-sessionStart>sessionLength/2) {
                  robot.addSpeech("Halfway there, keep going!");
                  halfwayMark = true;
              }
            }
           // }
        }
        
        if (state==ExerciseState.SESSION_TIMEOUT) {
            //long now = System.currentTimeMillis();
            //String strNow = dateFormat.format(new Date(now));
            //System.out.println(strNow + " monitoring session "+sessionNo);
            robot.log("Session timeout "+sessionNo);
               SessionRecord record = eu.analyseSession(sessionLength, mass);
                float calorieBurn = record.kineticEnergy * 0.239f / 1000;
               
               totalCalories+=calorieBurn;
               String format = df.format(calorieBurn);
//                 int format = Math.round(calorieBurn);
  
               //int calories = Math.round(calorieBurn);
               if (!greeted) {
                robot.addSpeech("OK, that time, you used "+format+ " calories.");
                greeted = true;
               }
                if (greeted && robot.speechFinished()) {
                    greeted = false;
                    if (sessionNo<3) {
                        state = ExerciseState.RESTART;
                    }
                    else {
                        state = ExerciseState.FINISH;
                    }
                }
            //}
           
        }
        
        if (state==ExerciseState.FINISH) {
             String format = df.format(totalCalories);
  //            int format = Math.round(totalCalories);
               if (!greeted) {
            robot.addSpeech("OK well done. You completed 3 sessions. In total you used "+format+ " calories. Thank you for playing with me, I hope to see you again some other time. Goodbye!");
               greeted = true;
              }
            
            if (greeted && robot.speechFinished()) {
                    state = ExerciseState.WAIT_FOR_PLAYER_TO_LEAVE;
                greeted = false;    
            }
        }
        
        if (state == ExerciseState.WAIT_FOR_PLAYER_TO_LEAVE) {
            activeUser = getActiveUser(users);
            if (activeUser==null) {
                state = ExerciseState.NOTHINGNESS;
            }
        }

        
        
    }

    boolean anyoneInZone(List<UserData> users) {
        boolean anyoneInZone = false;
        for (UserData user : users) {
            if (eu.newPlayZone(user)) {
              
            //if (eu.inPlayZone(user)) {
                anyoneInZone = true;
            }
        }
        return anyoneInZone;
    }

    UserData getActiveUser(List<UserData> users) {
        UserData chosenUser = null;
        for (UserData user : users) {
            if (eu.newPlayZone(user)) {
              
            //if (eu.inPlayZone(user)) {
                chosenUser = user;
            }
        }
        return chosenUser;
    }

}
